//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.ScientificWorkflow.ManagementStudioModels
{
    using System;
    using SR = Microsoft.Research.DataLayer;
    using System.Collections.ObjectModel;
    using System.Collections;
    using System.Linq;
    using System.Windows;

    /// <summary>
    /// A view friendly model for the Group.
    /// </summary>
    public class GroupViewModel : BaseRegMgrModel
    {
        #region Private fields

        private Guid id;


        private bool nonVirtualGroup;

        private bool status;

        private Guid displayId;

        private DateTime displayCreatedDate;

        private DateTime displayLastModifiedTime;

        private bool isDeleted;

        private bool isBuiltin;

        #endregion

        #region Constructors

        /// <summary>
        /// Constructor. An empty object will be created.
        /// </summary>
        public GroupViewModel()
        {
            this.IsSelected = false;
            this.Status = true;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="GroupViewModel"/> class. Initialize the model with information from the 
        /// passed category.
        /// </summary>
        /// <param name="parent">GroupViewModel</param>
        public GroupViewModel(SR.Group group, GroupViewModel parent)
        {
            this.Name = group.Name;
            this.Label = group.Name;
            this.Id = (group as SR.IObject).ID;
            this.Description = group.Description;
            this.CreatedBy = group.Created.User;
            this.CreatedDate = group.Created.When;
            this.LastModifiedBy = group.Updated.User;
            this.LastModifiedTime = group.Updated.When;
            this.Parent = parent;
            this.NonVirtualGroup = true;
            this.Status = group.Enabled;
            this.IsBuiltin = group.IsBuiltin;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="GroupViewModel"/> class.
        /// Initialize from the passed model.
        /// </summary>
        /// <param name="model">The model.</param>
        private GroupViewModel(GroupViewModel model)
        {
            if (model != null)
            {
                this.Name = model.Name;
                this.Label = model.Label;
                this.Id = model.id;
                this.Description = model.Description;
                this.CreatedBy = model.CreatedBy;
                this.CreatedDate = model.CreatedDate;
                this.LastModifiedBy = model.LastModifiedBy;
                this.LastModifiedTime = model.LastModifiedTime;
                this.IsSelected = model.IsSelected;
                this.Parent = model.Parent;
                this.NonVirtualGroup = model.NonVirtualGroup;
                this.Status = model.Status;
                if (model.Credentials != null)
                {
                    this.CloneCredentialCollection(model.Credentials);
                }
                if (model.Roles != null)
                {
                    this.CloneRoleCollection(model.Roles);
                }
                if (model.Users != null)
                {
                    this.CloneUserCollection(model.Users);
                }

                this.IsBuiltin = model.IsBuiltin;
            }
        }

        private void CloneRoleCollection(ObservableCollection<CredentialRoleModel> roleModel)
        {
            this.Roles = new ObservableCollection<CredentialRoleModel>();
            foreach (CredentialRoleModel model in roleModel)
            {
                CredentialRoleModel cloneModel = new CredentialRoleModel(model.RoleName, model.RoleSelected);
                this.Roles.Add(cloneModel);
            }
        }


        private void CloneCredentialCollection(ObservableCollection<LogOnCredentialModel> loginModels)
        {
            this.Credentials = new ObservableCollection<LogOnCredentialModel>();

            foreach (LogOnCredentialModel model in loginModels)
            {
                LogOnCredentialModel cloneModel = new LogOnCredentialModel(model.CredentialName, model.CredentialDisplayName);
                this.Credentials.Add(cloneModel);
            }
        }


        private void CloneUserCollection(ObservableCollection<SearchUserModel> searchModels)
        {
            this.Users = new ObservableCollection<SearchUserModel>();

            foreach (SearchUserModel model in searchModels)
            {
                SearchUserModel cloneModel = new SearchUserModel(model.UserName, model.DisplayName, model.DomainName);
                this.Users.Add(cloneModel);
            }
        }
        #endregion Constructors

        #region Public Properties

        /// <summary>
        /// Gets or sets the id.
        /// </summary>
        /// <value>The id.</value>
        public override Guid Id
        {
            get
            {
                return id;
            }
            set
            {
                id = value;
                this.DisplayId = value;
                this.RaisePropertyChanged("Id");
            }
        }

        /// <summary>
        /// Gets or sets the created date.
        /// </summary>
        /// <value>The created date.</value>
        public override DateTime CreatedDate
        {
            get
            {
                return base.CreatedDate;
            }
            set
            {
                base.CreatedDate = value;
                this.DisplayCreatedDate = value;
            }
        }

        /// <summary>
        /// Gets or sets the last modified time.
        /// </summary>
        /// <value>The last modified time.</value>
        public override DateTime LastModifiedTime
        {
            get
            {
                return base.LastModifiedTime;
            }
            set
            {
                base.LastModifiedTime = value;
                this.DisplayLastModifiedTime = value;
            }
        }

        /// <summary>
        /// Gets or set the Non Virtual Group
        /// </summary>
        public bool NonVirtualGroup
        {
            get
            {
                return this.nonVirtualGroup;
            }
            set
            {
                this.nonVirtualGroup = value;
                this.RaisePropertyChanged("NonVirtualGroup");
            }
        }

        /// <summary>
        /// Gets or sets the display id.
        /// </summary>
        /// <value>The display id.</value>
        public Guid DisplayId
        {
            get
            {
                if (this.displayId.Equals(Guid.Empty))
                {
                    return (Guid)DependencyProperty.UnsetValue;
                }

                return this.displayId;
            }
            set
            {
                this.displayId = value;
                this.RaisePropertyChanged("DisplayId");
            }
        }

        /// <summary>
        /// Gets or sets the display created date.
        /// </summary>
        /// <value>The display created date.</value>
        public DateTime DisplayCreatedDate
        {
            get
            {
                if (DateTime.MinValue.Equals(this.displayCreatedDate))
                {
                    return (DateTime)DependencyProperty.UnsetValue;
                }

                return this.displayCreatedDate;
            }
            set
            {
                this.displayCreatedDate = value;
                this.RaisePropertyChanged("DisplayCreatedDate");
            }
        }

        /// <summary>
        /// Gets or sets the display last modified time.
        /// </summary>
        /// <value>The display last modified time.</value>
        public DateTime DisplayLastModifiedTime
        {
            get
            {
                if (DateTime.MinValue.Equals(this.displayLastModifiedTime))
                {
                    return (DateTime)DependencyProperty.UnsetValue;
                }

                return this.displayLastModifiedTime;
            }
            set
            {
                this.displayLastModifiedTime = value;
                this.RaisePropertyChanged("DisplayLastModifiedTime");
            }
        }

        /// <summary>
        /// Gets or sets the Status.
        /// </summary>
        /// <value>The Status.</value>
        public bool Status
        {
            get
            {
                return status;
            }
            set
            {
                this.status = value;
                this.RaisePropertyChanged("Status");
            }
        }

        /// <summary>
        /// get and  private set Credentials
        /// </summary>
        public ObservableCollection<LogOnCredentialModel> Credentials { get; set; }

        /// <summary>
        /// get and  private set Roles
        /// </summary>
        public ObservableCollection<CredentialRoleModel> Roles { get; set; }

        /// <summary>
        /// get and  private set Groups
        /// </summary>
        public ObservableCollection<SearchUserModel> Users { get; set; }

        /// <summary>
        ///  A flag indication if the node is deleted.
        /// </summary>
        public bool IsDeleted
        {
            get
            {
                return isDeleted;
            }
            set
            {
                isDeleted = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this instance is builtin.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is builtin; otherwise, <c>false</c>.
        /// </value>
        public bool IsBuiltin
        {
            get
            {
                return isBuiltin;
            }
            set
            {
                isBuiltin = value;
                this.RaisePropertyChanged("IsBuiltin");
            }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Creates the clone.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns>
        /// The cloned model.
        /// </returns>
        public static GroupViewModel CreateClone(GroupViewModel model)
        {
            GroupViewModel clonedModel = null;
            if (null != model)
            {
                clonedModel = new GroupViewModel(model);
            }

            return clonedModel;
        }

        /// <summary>
        /// Serves as a hash function for a particular type.
        /// </summary>
        /// <returns>
        /// A hash code for the current <see cref="T:System.Object"/>.
        /// </returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        /// <summary>
        /// Checks the equality of Group Collection
        /// </summary>
        /// <param name="obj1">The obj1.</param>
        /// <param name="obj2">The obj2.</param>
        /// <returns></returns>
        public static bool CheckUserCollectionEquality(ObservableCollection<SearchUserModel> obj1, ObservableCollection<SearchUserModel> obj2)
        {

            if ((obj1 == null && obj2 == null))
            {
                return true;
            }

            if (obj1 != null && obj2 != null && obj1.Count != obj2.Count)
            {
                return false;
            }

            foreach (SearchUserModel model in obj1)
            {
                SearchUserModel resultModel = obj2.FirstOrDefault(p => p.UserName.Equals(model.UserName));
                if (resultModel == null)
                {
                    return false;
                }
            }

            return true;
        }


        /// <summary>
        /// Checks the equality of Roles Collection
        /// </summary>
        /// <param name="obj1">The obj1.</param>
        /// <param name="obj2">The obj2.</param>
        /// <returns></returns>
        public static bool CheckRolesCollectionEquality(ObservableCollection<CredentialRoleModel> obj1, ObservableCollection<CredentialRoleModel> obj2)
        {

            if ((obj1 == null && obj2 == null))
            {
                return true;
            }

            if (obj1 != null && obj2 != null && obj1.Count != obj2.Count)
            {
                return false;
            }

            foreach (CredentialRoleModel model in obj1)
            {
                CredentialRoleModel resultModel = obj2.FirstOrDefault(p => p.RoleName.Equals(model.RoleName) && p.RoleSelected != model.RoleSelected);
                if (resultModel != null)
                {
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// Checks the equality of Roles Collection
        /// </summary>
        /// <param name="obj1">The obj1.</param>
        /// <param name="obj2">The obj2.</param>
        /// <returns></returns>
        public static bool CheckCredentialCollectionEquality(ObservableCollection<LogOnCredentialModel> obj1, ObservableCollection<LogOnCredentialModel> obj2)
        {
            if ((obj1 == null && obj2 == null))
            {
                return true;
            }

            if (obj1 != null && obj2 != null && obj1.Count != obj2.Count)
            {
                return false;
            }

            foreach (LogOnCredentialModel model in obj1)
            {
                LogOnCredentialModel resultModel = obj2.FirstOrDefault(p => p.CredentialName.Equals(model.CredentialName));
                if (resultModel == null)
                {
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>.</param>
        /// <returns>
        /// true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, false.
        /// </returns>
        /// <exception cref="T:System.NullReferenceException">
        /// The <paramref name="obj"/> parameter is null.
        /// </exception>
        public override bool Equals(object obj)
        {
            bool equal = false;
            GroupViewModel equateParam = obj as GroupViewModel;
            if (equateParam != null &&
                equateParam.Id.Equals(this.Id) &&
                GroupViewModel.CheckEquality(equateParam.Description, this.Description) &&
                GroupViewModel.CheckEquality(equateParam.Name, this.Name) &&
                 GroupViewModel.CheckEquality(equateParam.Status, this.Status) &&
                 GroupViewModel.CheckUserCollectionEquality(equateParam.Users, this.Users) &&
                 GroupViewModel.CheckCredentialCollectionEquality(equateParam.Credentials, this.Credentials) &&
                 GroupViewModel.CheckRolesCollectionEquality(equateParam.Roles, this.Roles))
            {
                equal = true;
            }

            return equal;
        }


        /// <summary>
        /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </returns>
        public override string ToString()
        {
            return this.Name;
        }



        /// <summary>
        /// Updates the specified model.
        /// </summary>
        /// <param name="model">The model.</param>
        public override void Update(BaseRegMgrModel model)
        {
            GroupViewModel groupModel = model as GroupViewModel;
            if (groupModel != null)
            {
                this.Name = groupModel.Name;
                this.Label = groupModel.Label;
                this.Description = groupModel.Description;
                this.CreatedDate = groupModel.CreatedDate;
                this.CreatedBy = groupModel.CreatedBy;
                this.LastModifiedTime = groupModel.LastModifiedTime;
                this.LastModifiedBy = groupModel.LastModifiedBy;
                this.IsSelected = groupModel.IsSelected;
                this.Parent = model.Parent;
                this.Status = groupModel.Status;
                this.Roles = groupModel.Roles;
                this.Credentials = groupModel.Credentials;
                this.Users = groupModel.Users;
            }
        }

        /// <summary>
        /// Updates the specified category.
        /// </summary>
        /// <param name="category">The category.</param>
        public void Update(SR.Group group)
        {
            this.Name = group.Name;
            this.Label = string.IsNullOrEmpty(group.Name) ? group.Name : string.Empty; // category.Label;
            this.Id = (group as SR.IObject).ID;
            this.CreatedBy = group.Created.User;
            this.CreatedDate = group.Created.When;
            this.LastModifiedBy = group.Updated.User;
            this.LastModifiedTime = group.Updated.When;
            this.Status = group.Enabled;
            this.NonVirtualGroup = true;
        }

        #endregion Public Methods
    }


}

